crypto: BBS scheme for anonymous credentials with multiple presentations#1794
crypto: BBS scheme for anonymous credentials with multiple presentations#1794epoberezkin wants to merge 16 commits into
Conversation
There was a problem hiding this comment.
Adds Haskell FFI bindings to libbbs (BBS+ signatures over BLS12-381, SHA-256 suite). 6 newtypes + 6 API functions + tests. Submodules cbits/blst and cbits/libbbs (the latter as a SimpleX fork), with build wired through cabal at version 3.0 to use asm-sources for the BLST assembly. New commoncrypto flag swaps libbbs's getentropy for Apple's SecRandomCopyBytes to avoid iOS App Store rejection (ITMS-90338). Helper StrJSON added to Encoding.String to deduplicate ToJSON/FromJSON boilerplate. The FFI signatures match the C API documented in plans/2026-06-01-bbs-bindings.md, and withMessages correctly keeps each ByteString pinned via nested unsafeUseAsCStringLen for the duration of the C call.
Blocking
FromJSON skips length validation for BBSSecretKey, BBSPublicKey, BBSSignature, BBSProof. The module header claims "Any value parsed from untrusted input (StrEncoding / FromJSON) is length-validated". strDecode is — parseJSON isn't. StrJSON name is a newtype ... = StrJSON ByteString, so the derived FromJSON BBSSecretKey resolves strParseJSON at ByteString, runs raw base64urlP, and never touches the FixedBS/BBSProof instances. A 16-byte (or 0-byte, or 1000-byte) BBSSecretKey deserialised from JSON is then handed to withBS and bbsSign, which read the buffer assuming 32 bytes — heap OOB read in libbbs. See suggestion strjson-validate-fromjson. Fix is small: parameterise StrJSON over the wrapped type. No other code uses StrJSON.
Worth fixing
bbsProofGenallocates the output buffer from caller-controlled input without sanity checks.proofSz = 272 + 32 * (length msgs - length disclosedIdxs). Iflength disclosedIdxs > length msgs(or contains duplicates / out-of-range entries that libbbs counts literally),allocaBytesis called with a value smaller than what libbbs will write — and libbbs'sbbs_proof_genhas noproof_lenparameter, so the only thing protecting the buffer is libbbs's own internal validation. Exploitability depends on libbbs internals (submodule not checked out in this worktree, can't verify); regardless, a one-line guard beforeallocaBytesis cheap defense in depth.bbsProofVerifyaccepts mismatcheddisclosedIdxsanddisclosedMsgs. Parallel arrays of differing length get passed straight through to libbbs. Same defense-in-depth note: a precondition check (length disclosedIdxs == length disclosedMsgs) before the call is essentially free.- No JSON roundtrip test. All 8 BBS tests exercise the FFI directly with constructor values. The
StrJSONbug above would have been caught by a single property testparseJSON . toJSON ≡ Rightplus a "FromJSON rejects wrong-length input" negative test. plans/2026-06-01-bbs-bindings.mdis stale. It documentsbbsSign :: BBSSecretKey -> BBSPublicKey -> BBSHeader -> ...andbbsKeyGen :: IO (BBSSecretKey, BBSPublicKey), but the code dropped thepkparameter frombbsSignand inverted the tuple order inbbsKeyGen(the latter now returnsIO (Either String (BBSPublicKey, BBSSecretKey))). Either update the plan or drop it.
Notes (not changes)
BBSSecretKeyderivesShowshowing the raw bytes. Matches the existing convention (PrivateKey adoes the same inSimplex.Messaging.Crypto), so consistent; just noting it for awareness.c_bbs_sha256_ciphersuite :: Ptr (Ptr BBS_Ciphersuite)followed bypeekassumes the C symbol is a const pointer, not a const struct. If libbbs ever changes this to expose the struct directly,ciphersuitewould silently dereference garbage. The currentunsafePerformIO+NOINLINEpattern is fine for a pointer.withMessagesbuilds the parallel arrays via a list-reversing accumulator nested in N levels ofunsafeUseAsCStringLen. For BBS+ message counts (typically 3-5) this is fine; not a concern.- libbbs and blst submodules pull from third-party C/asm into the build. Worth confirming that whoever audits this is happy with vendoring
cbits/blst/src/server.c+cbits/blst/build/assembly.Sinto a library that previously had onlycbits/sha512.c+cbits/sntrup761.c.
No description provided.